<html t:ref="shell.html">
<li class="active" t:slot="nav3" t:ref=""/>
<div t:slot="body">
    <h4 style="margin-top: 0">1. <b>模板引擎</b></h4>
    <p>
        <a href="index.html">WebWheel</a>模板引擎使用广泛认可的<b style="color: #c0a16b">数据+模板=渲染结果</b>机制，
        引擎的核心类是<code>cn.webwheel.template.TemplateRenderer</code>和<code>cn.webwheel.template.RendererFactory</code>，
        后者是前者的工厂类，前者执行渲染，其渲染的签名为：
    </p>
    <pre class="prettyprint">public class TemplateRenderer {
    public void render(Writer writer, Map&lt;String, Object> ctx) throws IOException {...}
}</pre>
    <p>
        <code>writer</code>为输出流，<code>ctx</code>为变量环境，用于控制模板中的动态输出内容。
        在使用<code>RendererFactory</code>生成<code>TemplateRenderer</code>实例时传入模板
    </p>
    <pre class="prettyprint">public class RendererFactory {
    //构造方法，传入模板根路径，默认的文本编码，以及用于渲染js变量的工具类
    public RendererFactory(File root, String charset, ObjectMapper objectMapper) {...}

    //工厂方法，传入模板和文本编码，生成一个基于此模板文件的渲染类
    public TemplateRenderer create(String file, FileVisitor visitor, String charset) throws IOException {...}
}</pre>
    <p>
        <a href="index.html">WebWheel</a><a href="mvc.html">MVC</a>中使用<code>cn.webwheel.results.TemplateResultInterpreter</code>对此模板引擎进行了集成，
        使其可以作为动作方法的结果进行使用。
    </p>
    <h4>2. <b>模板页面结果与结果解释器</b></h4>
    <p>
        在框架中内置了模板引擎，并且在<code>Main.init()</code>方法中进行了配置
    </p>
    <pre class="prettyprint">interpret(TemplateResult.class).by(new TemplateResultInterpreter(root, null));</pre>
    <p>
        <code>TemplateResult</code>类接受两个构造参数，一个是模板的数据对象，一个是模板文件的路径，
        当路径为null时则模板文件的路径取当前HTTP请求的路径。例如:
    </p>
    <pre class="prettyprint">public class index {
    //此动作方法的HTTP请求路径为/index.html
    @Action
    public Object html() {
        return new TemplateResult(this);
        //等同于
        //return new TemplateResult(this, "/index.html");
    }
}</pre>
    <p>
        上例中，使用<code>this</code>作为模板渲染的数据来源对象，引擎将获取此对象的公共(public)属性和getter属性，作为数据传入<code>TemplateRenderer</code>。
    </p>
    <h4>3. <b>模板文件</b></h4>
    <p>
        <a href="index.html">WebWheel</a>模板引擎可以支持<code>html4</code>/<code>html5</code>/<code>xhtml</code>三种模板文件格式，
        要求html标签正确对称关闭，遵循格式规范。如：
    </p>
    <pre class="prettyprint">//html5
&lt;!DOCTYPE html>
&lt;html lang="en">
&lt;head>
    &lt;meta charset="UTF-8">
    &lt;title>Hello WebWheel&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>Hello WebWheel&lt;/h1>
&lt;/body>
&lt;/html></pre>
    <pre class="prettyprint">//html4
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
&lt;html lang="en">
&lt;head>
    &lt;meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    &lt;title>Hello WebWheel&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>Hello WebWheel&lt;/h1>
&lt;/body>
&lt;/html></pre>
    <pre class="prettyprint">//xhtml
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
&lt;html xmlns="http://www.w3.org/1999/xhtml">
&lt;head>
    &lt;meta content="text/html"/>
    &lt;title>Hello WebWheel&lt;/title>
&lt;/head>
&lt;body>
&lt;h1>Hello WebWheel&lt;/h1>
&lt;/body>
&lt;/html></pre>
    <h4>4. <b>数据对象</b></h4>
    <p>
        数据对象将被传入<code>TemplateResult</code>，<code>TemplateResultInterpreter</code>将利用反射机制获得数据对象的公开属性，
        并将其作为渲染数据传入到<code>TemplateRenderer</code>，以控制动态输出。例如：
    </p>
    <pre class="prettyprint">class PageModel {

    int innerVarA;

    //公共属性，名字为varB
    public String varB;

    //公共属性，名字为varA
    public int getVarA() {
        return innerVarA;
    }
}

public class index {
    @Action
    public Object html() {
        PageModel model = new PageModel();
        model.innerVarA = 1;
        model.varB = "Hello WebWheel";
        //使用model作为数据对象，其将被反射并构造变量表Map&String, Object>，包含
        //varA -> 1
        //varB -> "Hello WebWheel"
        return new TemplateResult(model);
    }
}</pre>
    <h4>5. <b>模板语法</b></h4>
    <p>
        这里将解释如何在<a href="index.html">WebWheel</a>模板引擎中控制动态渲染。
    </p>
    <h5>5.1 <b>动态输出</b></h5>
    <p>
        模板中可以使用变量进行动态输出，已实现在页面上显示动态内容。动态输出使用两个标记：<code>${}</code>和<code>#{}</code>，
        前者为转义输出，即将根据动态输出的上下文对输出后的文本进行必要的转义以使渲染正常；后者为原始输出，即不进行转义，直接输出动态变量的原始值。
    </p>
    <p>
        <code>${}</code>和<code>#{}</code>内放置求值表达式，使用<a href="http://mvel.codehaus.org/">MVEL</a>作为表达式引擎（类似OGNL），
        表达式语法可参考<a href="http://mvel.codehaus.org/Language+Guide+for+2.0">官网</a>。
        例如如下数据对象和模板：
    </p>
    <pre class="prettyprint">class PageModel {
    public String naughty = "say &lt; \"Hello WebWheel\"";
}</pre>
    <pre class="prettyprint">&lt;!-- 在标签内和属性值中 -->
&lt;span title="&#36;{naughty}">&#36;{naughty}&lt;/span>
&lt;span title="&#35;{naughty}">&#35;{naughty}&lt;/span>

&lt;!-- 在脚本中 -->
&lt;script>
    s = &#36;{naughty};
    s = &#35;{naughty};

    s = "&#36;{naughty}";
    s = "&#35;{naughty}"
&lt;/script>

&lt;!-- 在地址中 -->
&lt;a href="index.jsp?v=&#36;{naughty}">link&lt;/a>
&lt;a href="index.jsp?v=&#35;{naughty}">link&lt;/a></pre>
    <p>
        此模板和数据对象组合的渲染结果将为：
    </p>
    <pre class="prettyprint">&lt;!-- 在标签内和属性值中 -->
&lt;span title="say &lt; &#38;quot;Hello WebWheel&#38;quot;">say &#38;lt; "Hello WebWheel"&lt;/span>
&lt;span title="say &lt; "Hello WebWheel"">say &lt; "Hello WebWheel"&lt;/span>

&lt;!-- 在脚本中 -->
&lt;script>
    s = "say &lt; \"Hello WebWheel\"";
    s = say &lt; "Hello WebWheel";

    s = "say &lt; \"Hello WebWheel\"";
    s = "say &lt; "Hello WebWheel""
&lt;/script>

&lt;!-- 在地址中 -->
&lt;a href="index.jsp?v=say+-%3E+%22Hello+WebWheel%22">link&lt;/a>
&lt;a href="index.jsp?v=say &lt; "Hello WebWheel"">link&lt;/a>
</pre>
    <p>
        可见，<code>${}</code>可以感知上下文，使页面输出正常，同时也减少了网站被攻击的风险。
    </p>
    <h5>5.2 <b>逻辑控制</b></h5>
    <p>
        <a href="index.html">WebWheel</a>模板引擎具有简单但完备的逻辑控制功能，通过引入<code>w:</code>标签属性，
        引擎可以对html无侵入的实现逻辑控制。引擎<b style="color: #c0a16b">所有</b>的逻辑控制方法列举如下：
    </p>
    <pre class="prettyprint">&lt;!--是否输出标签-->
&lt;span w:="1+1==2">1+1==2&lt;/span>
&lt;span w:="1+1==3">1+1==2&lt;/span>

&lt;!--是否输出标签属性-->
&lt;select>
    &lt;option selected="&#36;{1+1==2}">1+1=2&lt;/option>
    &lt;option selected="&#36;{1+1==3}">1+1=3&lt;/option>
&lt;/select>
&lt;!--等同于-->
&lt;select>
    &lt;option selected="&#36;{1+1==2?'':null}">1+1=2&lt;/option>
    &lt;option selected="&#36;{1+1==3?'':null}">1+1=3&lt;/option>
&lt;/select>

&lt;!--循环-->
&lt;select>
    &lt;option w:item="['Hello','Web','Wheel']">&#36;{item_idx} - &#36;{item}&lt;/option>
&lt;/select>

&lt;!--变量定义，禁止循环释义-->
&lt;div w:a="&#35;{1+1}">
    &lt;span>1+1=&#36;{a}&lt;/span>
&lt;/div></pre>
    <p>
        当<code>w:</code>后没有任何内容时，其值如果为boolean类型，则会根据boolean值决定是否输出整个标签，如果是其他类型的值，
        相当于使用<code>${}</code>输出动态内容。
    </p>
    <p>
        当标签属性值全部由<code>${}</code>包围时，表达式的求值结果可控制是否输出对应标签属性，当值为false或null时不输出标签属性。
    </p>
    <p>
        <code>w:</code>后可定义循环节变量的名称，如上述的<code>item</code>，循环标记的标签内部可使用<code>item</code>对循环节进行引用，
        并且可以使用<code>item_idx</code>来得到索引值（从0开始）。可以实现循环的表达式值包括数组、<code>Iterable</code>和<code>Iterator</code>。
        其他类型等同于变量定义。
    </p>
    <p>
        当<code>w:</code>标签属性的值由<code>#{}</code>包围时，则框架将强制不使用循环的含义对其解释，相当于变量定义，变量的作用域在定义变量的标签内。
    </p>
    <p>
        上述模板在经过引擎处理后，将被渲染为：
    </p>
    <pre class="prettyprint">&lt;!--是否输出标签-->
&lt;span>1+1==2&lt;/span>


&lt;!--是否输出标签属性-->
&lt;select>
    &lt;option selected="">1+1=2&lt;/option>
    &lt;option>1+1=3&lt;/option>
&lt;/select>
&lt;!--等同于-->
&lt;select>
    &lt;option selected="">1+1=2&lt;/option>
    &lt;option>1+1=3&lt;/option>
&lt;/select>

&lt;!--循环-->
&lt;select>
    &lt;option>0 - Hello&lt;/option>&lt;option>1 - Web&lt;/option>&lt;option>2 - Wheel&lt;/option>
&lt;/select>

&lt;!--变量定义，禁止循环释义-->
&lt;div>
    &lt;span>1+1=2&lt;/span>
&lt;/div></pre>
    <h5>5.3 <b>模板复用</b></h5>
    <p>
        <a href="index.html">WebWheel</a>模板引擎使用<b style="color: #c0a16b">可嵌套</b>的页面块来实现模板的复用，
        模板使用<code>t:ref</code>与<code>t:slot</code>标签属性来实现引用与定位。模板复用在动态输出之前进行，所以动态内容的标记同样可以得到复用。
    </p>
    <pre class="prettyprint">&lt;!--定义位置-->
&lt;div t:slot="abc">
    Hello WebWheel
&lt;/div>
&lt;!--引用-->
&lt;div t:ref="#abc">&lt;/div></pre>
    <p>
        这是一个最简单的模板复用例子，下面的div块将引用本页面的<code>abc</code>位置的内容，<code>t:slot="abc"</code>定义了标签位置，
        <code>t:ref="#abc"</code>引用当前页面的<code>abc</code>并且替换本标签。上述模板的渲染结果为：
    </p>
    <pre class="prettyprint">&lt;!--定义位置-->
&lt;div>
    Hello WebWheel
&lt;/div>
&lt;!--引用-->
&lt;div>
    Hello WebWheel
&lt;/div></pre>
    <p>
        <code>t:slot</code>标签本身可以嵌套使用，引用时通过<code>#</code>分隔符进行嵌套定位，如：
    </p>
    <pre class="prettyprint">&lt;!--定义位置-->
&lt;div t:slot="abc">
    span之外
    &lt;span t:slot="def">Hello WebWheel&lt;/span>
&lt;/div>
&lt;!--引用-->
&lt;div t:ref="#abc#def">&lt;/div></pre>
    <p>
        渲染为
    </p>
    <pre class="prettyprint">&lt;!--定义位置-->
&lt;div>
    span之外
    &lt;span>Hello WebWheel&lt;/span>
&lt;/div>
&lt;!--引用-->
&lt;span>Hello WebWheel&lt;/span></pre>
    <p>
        <code>t:ref</code>也可引用其他模板文件的内容，例如<code>abc.html</code>页面内可以使用<code>t:ref="def.html"</code>来引用<code>def.html</code>页面的全部内容，
        或者使用<code>t:ref="def.html#def#other"</code>来引用<code>def.html</code>页面内的相应位置的内容。
    </p>
    <p>
        <a href="index.html">WebWheel</a>模板引擎的模板复用机制的强大之处在于<code>t:slot</code>与<code>t:ref</code>可以联合使用达到准确易用的页面块复用。
        以下将展示一个常见的页面复用的场景，三个模板文件，两个页面。<code>s.html</code>代表外壳页面的模板文件，<code>page1.html</code>和<code>page2.html</code>为两个页面所对应的模板文件，
        在这两个模板文件中将引用<code>s.html</code>的内容，并且根据需要替换本页面独有的内容。
    </p>
    <pre class="prettyprint">//s.html
&lt;!DOCTYPE html>
&lt;html>
&lt;head lang="en">
    &lt;meta charset="UTF-8">
    &lt;title t:slot="title">标题&lt;/title>
    &lt;style>
        div {
            border: red 1px solid;
            margin: 10px;
            padding: 10px;
        }
    &lt;/style>
&lt;/head>
&lt;body>
&lt;div t:slot="header">
    默认头部
&lt;/div>
&lt;div t:slot="body">
    &lt;div t:slot="nav" style="width: 200px;float: left">
        &lt;a href="page1.html" t:slot="nav1">页面一&lt;/a>
        &lt;br>
        &lt;a href="page2.html" t:slot="nav2">页面二&lt;/a>
    &lt;/div>
    &lt;div t:slot="main" style="margin-left: 240px;height: 300px">
        内容区
    &lt;/div>
&lt;/div>
&lt;div t:slot="footer">
    默认底部
&lt;/div>
&lt;/body>
&lt;/html></pre>
    <p>
        此模板为完全的静态可预览模板，使用浏览器直接打开此模板文件，显示效果为：<br>
        <img src="imgs/shtml.jpg">
    </p>
    <p>
        页面一的模板文件为：
    </p>
    <pre class="prettyprint">//page1.html
&lt;html t:ref="s.html">
&lt;title t:slot="title">Page1 Title&lt;/title>
&lt;div t:slot="header">Page1的头部&lt;/div>
&lt;div t:slot="body" t:ref="">
    &lt;div t:slot="nav" t:ref="">
        &lt;div t:slot="nav1" t:ref="" style="color: green">&lt;/div>
    &lt;/div>
    &lt;div t:slot="main">
        我是Page1的内容
    &lt;/div>
&lt;/div>
&lt;/html></pre>
    <p>
        页面一引用了<code>s.html</code>的全部内容，并且替换了<code>title</code>标签、<code>header</code>部分以及内容区，
        并且为<code>nav1</code>位置的标签增加了style属性。由模板中可见，当<code>t:ref</code>的值为空时，意为引用对应的<code>t:slot</code>部分内容。
        页面一的最终渲染效果为：<br>
        <img src="imgs/page1.jpg">
    </p>
    <p>
        页面二的模板文件为：
    </p>
    <pre class="prettyprint">//page2.html
&lt;html t:ref="s.html">
&lt;title t:slot="title">Page2 Title&lt;/title>
&lt;div t:slot="body" t:ref="">
    &lt;div t:slot="nav" t:ref="">
        &lt;div t:slot="nav2" t:ref="" style="color: green">&lt;/div>
    &lt;/div>
    &lt;div t:slot="main">
        我是Page2的内容
    &lt;/div>
&lt;/div>
&lt;div t:slot="footer">Page2的底部&lt;/div>
&lt;/html></pre>
    <p>
        同页面一类似，页面二也引用了外壳模板，并且替换了独有的内容，其渲染效果为：<br>
        <img src="imgs/page2.jpg">
    </p>
    <p>
        由上可以看到，模板引擎的复用机制可以灵活的控制复用内容以及范围，并且最大化的实现了复用，更可以有效的使后端程序脱离前台页面展示逻辑。
    </p>
    <div style="text-align: center">
        <a href="userguide.html">返回用户手册</a>
    </div>
</div>
</html>